#include "drv_iic.h"
#include "drv_systick.h"
/**********************************************************
函数名：drv_iic_init

函数功能：IIC初始化

输入参数：无

输出参数：无

其它说明：	//PB6 scl
			//pb7 sda

**********************************************************/
void drv_iic_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//开时钟

	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//GPIO参数配置
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);

}
/**********************************************************
函数名：drv_sda_in

函数功能：将SDA设置为输入

输入参数：无

输出参数：无

其它说明：	

**********************************************************/
void drv_sda_in(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/**********************************************************
函数名：drv_sda_in

函数功能：将SDA设置为输出

输入参数：无

输出参数：无

其它说明：	

**********************************************************/
void drv_sda_out(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);


}
/**********************************************************
函数名：drv_iic_start

函数功能：产生IIC的起始信号

输入参数：无

输出参数：无

其它说明：	当时钟线为高时，数据线由高电平变为低电平，产生一个有效的下降沿

**********************************************************/
void drv_iic_start(void)
{
	SCL_L;
	drv_sda_out();

	SDA_H;
	SCL_H;
	drv_systick_delayus(5);
	SDA_L;
	drv_systick_delayus(5);
	SCL_L;

}
/**********************************************************
函数名：drv_iic_stop

函数功能：产生IIC的停止信号

输入参数：无

输出参数：无

其它说明：	当时钟线为高时，数据线由低电平变为高电平，产生一个有效的上升沿

**********************************************************/
void drv_iic_stop(void)
{
	SCL_L;
	drv_sda_out();

	SDA_L;
	SCL_H;
	drv_systick_delayus(5);
	SDA_H;
	drv_systick_delayus(5);
}
/**********************************************************
函数名：drv_iic_waitACK

函数功能：等待ACK

输入参数：无

输出参数：无

其它说明：	把时钟线拉高，获取数据线上的数据（高电平/低电平），如果长时间没有等到ACK，那么
			主动停止此次通信

**********************************************************/
uint8_t drv_iic_waitACK(void)
{
	uint8_t timeout=0;
	SCL_L;
	drv_sda_in();

	SCL_H;
	while(SDA_READ)
	{
		timeout++;
		if(timeout > 300)
		{
			drv_iic_stop();
			return NOACK;
		}
	}
	return ACK;
}
/**********************************************************
函数名：drv_iic_sendACK

函数功能：发送ACK

输入参数：无

输出参数：无

其它说明：	当时钟线为高电平时，数据线为有效的低电平

**********************************************************/

void drv_iic_sendACK(void)
{
	SCL_L;
	drv_sda_out();

	SDA_L;
	SCL_H;
	drv_systick_delayus(5);
	SCL_L;	
}
/**********************************************************
函数名：drv_iic_sendNOACK

函数功能：发送ACK

输入参数：无

输出参数：无

其它说明：	当时钟线为高电平时，数据线为有效的高电平

**********************************************************/
void drv_iic_sendNOACK(void)
{
	SCL_L;
	drv_sda_out();

	SDA_H;
	SCL_H;
	drv_systick_delayus(5);
	SCL_L;	

}
/**********************************************************
函数名：drv_iic_sendByte

函数功能：发送ACK

输入参数：需要发送的数据

输出参数：无

其它说明：	当时钟线为高时，数据线上的电平必须要恒稳定
			当时钟线为低时，数据线上的电平允许发送改变
			高位先行

**********************************************************/
void drv_iic_sendByte(uint8_t Byte)
{
	uint8_t i=0;
	SCL_L;
	drv_sda_out();
	for(i=0; i<8; i++)
	{
		if(Byte & 0x80)//如果为真说明需要发送的数据的位数是高电平，否则为低电平
		{
			SDA_H;
		}
		else
		{
			SDA_L;
		}
		SCL_H;
		drv_systick_delayus(5);
		SCL_L;
		drv_systick_delayus(5);
		Byte = Byte <<1;//准备发送下一位数据
	}
	SCL_L;
}
/**********************************************************
函数名：drv_iic_readByte

函数功能：读取数据

输入参数：发生ACK的标志            1：发送NOACK      0:发送ACK

输出参数：读取到的数据

其它说明：	当时钟线为高时，数据线上的电平必须要恒稳定
			当时钟线为低时，数据线上的电平允许发送改变
			高位先行

**********************************************************/
uint8_t drv_iic_readByte(uint8_t ack_flag)
{
	uint8_t readdata=0,i=0;
	SCL_L;
	drv_sda_in();
	
	for(i=0; i<8;i++)
	{
		readdata = readdata<<1;//先左移一次，否则数据会多移出一次
		SCL_H;
		if(SDA_READ)
		{
			readdata = readdata | 0x01;
		}
		drv_systick_delayus(5);
		SCL_L;
		drv_systick_delayus(5);
	}
	if(ack_flag == ACK)
	{
		drv_iic_sendACK();
	}
	else
	{
		drv_iic_sendNOACK();

	}
	SCL_L;
	return readdata;

}
